<?PHP
    # Original PHP code by Chirp Internet: www.chirp.com.au
    # Please acknowledge use of this code by including this header.

    class myAtomParser
    {
        # keeps track of current and preceding elements
        var $tags = array();

        # array containing all feed data
        var $output = array();

        # return value for display functions
        var $retval = "";

        var $encoding = array();

        # default caching time (50min)

        # constructor for new object
        function myAtomParser($file, $cache_dir = '', $cache_time = 3000)
        {
            // Cache routine from lastRSS.php
            if($cache_dir != '') {
                $cache_file = $cache_dir . '/atomcache_' . md5($file);
                $timedif = @(time() - filemtime($cache_file));
                if($timedif < $cache_time) {
                    // New Enough
                    $this->output = unserialize(join('', file($cache_file)));
                    //set 'cached' to 1 only if cached file is correct
                    if($this->output) $this->output['cached'] = 1;
                } else {
                    // cached file is too old, create new
                    $this->Parse($file);
                    $serialized = serialize($this->output);
                    if ($f = @fopen($cache_file, 'w')) {
                        fwrite ($f, $serialized, strlen($serialized));
                        fclose($f);
                    }
                    if ($this->output) $this->output['cached'] = 0;
                }
            }
            // If CACHE DISABLED >> load and parse the file directly
            else {
                $this->Parse($file);
                if($this->output) $this->output['cached'] = 0;
            }
            return;
        }

        // Old Constructor
        function Parse($file) {
            # instantiate xml-parser and assign event handlers
            $xml_parser = xml_parser_create("");
            xml_set_object($xml_parser, $this);
            xml_set_element_handler($xml_parser, "startElement", "endElement");
            xml_set_character_data_handler($xml_parser, "parseData");

            # open file for reading and send data to xml-parser
            $fp = fopen($file, "r") or die("myAtomParser: Could not open $file for input");
            while($data = fread($fp, 4096)) {
                xml_parse($xml_parser, $data, feof($fp)) or die(
                    sprintf("myAtomParser: Error <b>%s</b> at line <b>%d</b><br>",
                    xml_error_string(xml_get_error_code($xml_parser)),
                    xml_get_current_line_number($xml_parser))
                );
            }
            fclose($fp);

            # dismiss xml parser
            xml_parser_free($xml_parser);
        }

        function startElement($parser, $tagname, $attrs)
        {
            if($this->encoding) {
                # content is encoded - so keep elements intact
                $tmpdata = "<$tagname";
         if($attrs) foreach($attrs as $key => $val) $tmpdata .= " $key=\"$val\"";
                $tmpdata .= ">";
                $this->parseData($parser, $tmpdata);
            } else {
                if($attrs['HREF'] && $attrs['REL'] && $attrs['REL'] == 'alternate') {
                    $this->startElement($parser, 'LINK', array());
                    $this->parseData($parser, $attrs['HREF']);
                    $this->endElement($parser, 'LINK');
                }
                if($attrs['TYPE']) $this->encoding[$tagname] = $attrs['TYPE'];

                # check if this element can contain others - list may be edited
                if(preg_match("/^(FEED|ENTRY)$/", $tagname)) {
                    if($this->tags) {
                        $depth = count($this->tags);
                        list($parent, $num) = each($tmp = end($this->tags));
                        if($parent) $this->tags[$depth-1][$parent][$tagname]++;
                    }
                    array_push($this->tags, array($tagname => array()));
                } else {
                    # add tag to tags array
                    array_push($this->tags, $tagname);
                }
            }
        }

        function endElement($parser, $tagname)
        {
            # remove tag from tags array
            if($this->encoding) {
                if(isset($this->encoding[$tagname])) {
                    unset($this->encoding[$tagname]);
                    array_pop($this->tags);
                } else {
                    if(!preg_match("/(BR|IMG)/", $tagname)) $this->parseData($parser, "</$tagname>");
                }
            } else {
                array_pop($this->tags);
            }
        }

        function parseData($parser, $data)
        {
            # return if data contains no text
            if(!trim($data)) return;
            $evalcode = "\$this->output";
            foreach($this->tags as $tag) {
                if(is_array($tag)) {
                    list($tagname, $indexes) = each($tag);
                    $evalcode .= "[\"$tagname\"]";
                    if(${$tagname}) $evalcode .= "[" . (${$tagname} - 1) . "]";
                    if($indexes) extract($indexes);
                } else {
                    if(preg_match("/^([A-Z]+):([A-Z]+)$/", $tag, $matches)) {
                        $evalcode .= "[\"$matches[1]\"][\"$matches[2]\"]";
                    } else {
                        $evalcode .= "[\"$tag\"]";
                    }
                }
            }

            if(isset($this->encoding['CONTENT']) && $this->encoding['CONTENT'] == "text/plain") {
                $data = "<pre>$data</pre>";
            }

            eval("$evalcode .= '" . addslashes($data) . "';");
        }

        # display a single feed as HTML
        function display_feed($data, $limit)
        {
            extract($data);
            if($TITLE) {
                # display feed information
                $this->retval .= "<h1>";
                if($LINK) $this->retval .= "<a href=\"$LINK\" target=\"_blank\">";
                $this->retval .= stripslashes($TITLE);
                if($LINK) $this->retval .= "</a>";
                $this->retval .= "</h1>\n";
                if($TAGLINE) $this->retval .= "<P>" . stripslashes($TAGLINE) . "</P>\n\n";
                $this->retval .= "<div class=\"divider\"><!-- --></div>\n\n";
            }
            if($ENTRY) {
                # display feed entry(s)
                foreach($ENTRY as $item) {
                    $this->display_entry($item, "FEED");
                    if(is_int($limit) && --$limit <= 0) break;
                }
            }
        }

        # display a single entry as HTML
        function display_entry($data, $parent)
        {
            extract($data);
            if(!$TITLE) return;

            $this->retval .=    "<p><b>";
            if($LINK) $this->retval .=    "<a href=\"$LINK\" target=\"_blank\">";
            $this->retval .= stripslashes($TITLE);
            if($LINK) $this->retval .= "</a>";
            $this->retval .=    "</b>";
            if($ISSUED) $this->retval .= " <small>($ISSUED)</small>";
            $this->retval .=    "</p>\n";

            if($AUTHOR) {
                $this->retval .=    "<P><b>Author:</b> " . stripslashes($AUTHOR['NAME']) . "</P>\n\n";
            }
            if($CONTENT) {
                $this->retval .=    "<P>" . stripslashes($CONTENT) . "</P>\n\n";
            } elseif($SUMMARY) {
                $this->retval .=    "<P>" . stripslashes($SUMMARY) . "</P>\n\n";
            }
        }

        function fixEncoding($input, $output_encoding)
        {
            return $input;
            // For some reason this is missing in the php4 in NMT
            $encoding = mb_detect_encoding($input);
            switch($encoding) {
                case 'ASCII':
                case $output_encoding:
                    return $input;
                case '':
                    return mb_convert_encoding($input, $output_encoding);
                default:
                    return mb_convert_encoding($input, $output_encoding, $encoding);
            }
        }

        # display entire feed as HTML
        function getOutput($limit=false, $output_encoding='UTF-8')
        {
            $this->retval = "";
            $start_tag = key($this->output);

            switch($start_tag) {
                case "FEED":
                    foreach($this->output as $feed) $this->display_feed($feed, $limit);
                    break;
                default:
                    die("Error: unrecognized start tag '$start_tag' in getOutput()");
            }

            return $this->fixEncoding($this->retval, $output_encoding);
        }

        # return raw data as array
        function getRawOutput($output_encoding='UTF-8')
        {
            return $this->fixEncoding($this->output, $output_encoding);
        }
    }
?>
